# Copyright (C) 2001-2007, 2011 The Written Word, Inc.
# Copyright (C) 2000-2001 The Written Word, LLC
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# $Id: __init__.py 791 2012-03-17 04:53:31Z china $

import fchksum
import os
import stat
import sys

import prog

class Archive:
  def __init__ (self, path):
    self.path = path			# path to archive file

    self.arg = None			# extra args
    self.build_prefix = None		# path to build directory
    self.srcdir = None			# path to source files
    self.depot = None			# depot containing archive

    self.bash_path = None		# path to 'bash' program

    self.environ = []
    self.size = 0
    self.checksum = None

  # path to XML .sb file (because this is an archive file, we
  # print the archive path and member in the archive).
  def sbdb_path (self, member):
    return self.path + '(' + member + ')'

  # extract file from archive
  def extract (self, member, dest = None):
    pass

  # make sure we have permission to write to build directory
  def write_build_prefix (self, path = None):
    if not path:
      path = self.path

    try:
      fh = open (self.build_prefix + '/.tww', 'w')
      fh.close ()
      os.remove (self.build_prefix + '/.tww')
    except (IOError, OSError), msg:
      raise prog.ProgArchiveError ('unable to unpack ' + path +
      ' to ' + self.build_prefix + ' because you do not have correct \
permission to write to this directory.')

  def verify_md5_sig (self):
    if not os.path.exists (self.path):
      raise prog.ProgPayloadNotFound

    if self.size:
      size = os.lstat (self.path)[stat.ST_SIZE]
      if self.size != size:
        raise prog.ProgPayloadInvalidSize (size)

    if self.checksum:
      checksum = fchksum.fmd5t (self.path)[0]
      if self.checksum != checksum:
        raise prog.ProgPayloadInvalidChecksum (checksum)

def pipe_two_commands (pipe1_cmd, pipe1_args, pipe2_cmd, pipe2_args,
                       environ):
  pipe1_r, pipe1_w = os.pipe ()
  pipe1 = os.fork ()
  if pipe1 == 0:
    os.close (pipe1_r)
    os.dup2 (pipe1_w, 1)
    os.close (pipe1_w)
  
    os.execvpe (pipe1_cmd, [ pipe1_cmd ] + pipe1_args, environ)

  pipe2 = os.fork ()
  if pipe2 == 0:
    os.close (pipe1_w)
    os.dup2 (pipe1_r, 0)
    os.close (pipe1_r)

    os.execvpe (pipe2_cmd, [ pipe2_cmd ] + pipe2_args, environ)

  _exit = 0

  wait_pids = [ pipe1, pipe2 ]
  while wait_pids:
    if pipe1 in wait_pids:
      _pid, _status = os.waitpid (pipe1, os.WNOHANG)
      _status >>= 8
      if _pid == pipe1:
        _exit |= _status
        os.close (pipe1_w)
        wait_pids.remove (pipe1)

    if pipe2 in wait_pids:
      _pid, _status = os.waitpid (pipe2, os.WNOHANG)
      _status >>= 8
      if _pid == pipe2:
        _exit |= _status
        os.close (pipe1_r)
        wait_pids.remove (pipe2)

  return _exit

def init (path, type = None):
  if not type:
    # identify based on first few bytes from path
    try:
      fh = open (path, 'rb')
      archive_type = fh.read (6)
      fh.close ()
    except (IOError, OSError), msg:
      raise prog.ProgArchiveError (str (msg))

    # zip or XML archive
    archive = None
    if len (archive_type) != 6:
      raise prog.ProgArchiveInvalidError (path + ' is not a valid \
archive. could not determine type by inspecting the first 6 bytes.')
    if archive_type == '\x50\x4b\x03\x04\x14\x00':
      exec 'import prog.archive.zip'
      exec 'archive = prog.archive.zip.Archive (path)'

    return archive

  # .tar.gz archive
  if path[-7:] == '.tar.gz' or path[-4:] == '.tgz' or \
  path[-6:] == '.tar.Z':
    exec 'import prog.archive.tar'
    exec 'archive = prog.archive.tar.ArchiveGzip (path)'
  # .tar.bz2 archive
  elif path[-8:] == '.tar.bz2':
    exec 'import prog.archive.tar'
    exec 'archive = prog.archive.tar.ArchiveBzip2 (path)'
  # .tar.xz archive
  elif path[-7:] == '.tar.xz':
    exec 'import prog.archive.tar'
    exec 'archive = prog.archive.tar.ArchiveLZMA (path)'
  # .tar archive
  elif path[-4:] == '.tar':
    exec 'import prog.archive.tar'
    exec 'archive = prog.archive.tar.Archive (path)'
  # .cpio.gz archive
  elif path[-8:] == '.cpio.gz' or path[-7:] == '.cpio.Z':
    exec 'import prog.archive.cpio'
    exec 'archive = prog.archive.cpio.ArchiveGzip (path)'
  # .cpio.bz2 archive
  elif path[-9:] == '.cpio.bz2':
    exec 'import prog.archive.cpio'
    exec 'archive = prog.archive.cpio.ArchiveBzip2 (path)'
  # .cpio archive
  elif path[-5:] == '.cpio':
    exec 'import prog.archive.cpio'
    exec 'archive = prog.archive.cpio.Archive (path)'
  # .zip archive
  elif path[-4:] == '.zip' or path[-4:] == '.jar':
    exec 'import prog.archive.zip'
    exec 'archive = prog.archive.zip.Archive (path)'
  elif path[-3:] == '.sh':
    exec 'import prog.archive.sh'
    exec 'archive = prog.archive.sh.Archive (path)'
  elif path[-3:] == '.gz' and type == 'patch':
    exec 'import prog.archive.patch'
    exec 'archive = prog.archive.patch.ArchiveGzip (path)'
  elif path[-6:] == '.patch' or type == 'patch':
    exec 'import prog.archive.patch'
    exec 'archive = prog.archive.patch.Archive (path)'
  else:
    raise prog.ProgArchiveError ('Unable to determine file type \
of archive: ' + path)

  return archive
